import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * 智能天气数据缓存管理器
 * 提供多源数据缓存、验证、聚合和可靠性统计功能
 */
public class WeatherDataCache {
    
    // 缓存数据结构
    public static class CachedWeatherData {
        private final WeatherData data;
        private final String sourceId;
        private final LocalDateTime timestamp;
        private final long latency;
        
        public CachedWeatherData(WeatherData data, String sourceId, long latency) {
            this.data = data;
            this.sourceId = sourceId;
            this.timestamp = LocalDateTime.now();
            this.latency = latency;
        }
        
        public WeatherData getData() { return data; }
        public String getSourceId() { return sourceId; }
        public LocalDateTime getTimestamp() { return timestamp; }
        public long getLatency() { return latency; }
        
        public boolean isExpired(int cacheMinutes) {
            return ChronoUnit.MINUTES.between(timestamp, LocalDateTime.now()) > cacheMinutes;
        }
    }
    
    // API源可靠性统计
    public static class SourceReliabilityStats {
        private AtomicLong successCount = new AtomicLong(0);
        private AtomicLong failureCount = new AtomicLong(0);
        private AtomicLong totalLatency = new AtomicLong(0);
        private AtomicLong requestCount = new AtomicLong(0);
        private LocalDateTime lastSuccess;
        private LocalDateTime lastFailure;
        
        public void recordSuccess(long latency) {
            successCount.incrementAndGet();
            requestCount.incrementAndGet();
            totalLatency.addAndGet(latency);
            lastSuccess = LocalDateTime.now();
        }
        
        public void recordFailure() {
            failureCount.incrementAndGet();
            requestCount.incrementAndGet();
            lastFailure = LocalDateTime.now();
        }
        
        public double getReliabilityScore() {
            long total = requestCount.get();
            if (total == 0) return 0.0;
            
            double successRate = (double) successCount.get() / total;
            double avgLatency = total > 0 ? (double) totalLatency.get() / successCount.get() : 5000.0;
            
            // 计算可靠性分数：成功率权重70%，延迟权重30%
            double latencyScore = Math.max(0, 1.0 - (avgLatency / 5000.0)); // 5秒为最差延迟
            return (successRate * 0.7) + (latencyScore * 0.3);
        }
        
        public double getAverageLatency() {
            long success = successCount.get();
            return success > 0 ? (double) totalLatency.get() / success : 0.0;
        }
        
        // Getters
        public long getSuccessCount() { return successCount.get(); }
        public long getFailureCount() { return failureCount.get(); }
        public LocalDateTime getLastSuccess() { return lastSuccess; }
        public LocalDateTime getLastFailure() { return lastFailure; }
    }
    
    private static final int DEFAULT_CACHE_MINUTES = 10; // 缓存10分钟
    private static final double TEMPERATURE_VARIANCE_THRESHOLD = 5.0; // 温度差异阈值5°C
    private static final double HUMIDITY_VARIANCE_THRESHOLD = 15.0; // 湿度差异阈值15%
    
    // 缓存存储
    private final ConcurrentHashMap<String, CachedWeatherData> currentWeatherCache;
    private final ConcurrentHashMap<String, CachedWeatherData[]> forecastCache;
    private final ConcurrentHashMap<String, SourceReliabilityStats> reliabilityStats;
    
    public WeatherDataCache() {
        this.currentWeatherCache = new ConcurrentHashMap<>();
        this.forecastCache = new ConcurrentHashMap<>();
        this.reliabilityStats = new ConcurrentHashMap<>();
    }
    
    /**
     * 缓存当前天气数据
     */
    public void cacheCurrentWeather(String locationKey, WeatherData data, String sourceId, long latency) {
        String cacheKey = generateCacheKey(locationKey, sourceId);
        CachedWeatherData cached = new CachedWeatherData(data, sourceId, latency);
        currentWeatherCache.put(cacheKey, cached);
        
        // 更新可靠性统计
        reliabilityStats.computeIfAbsent(sourceId, k -> new SourceReliabilityStats())
                       .recordSuccess(latency);
        
        System.out.println("Cached current weather from " + sourceId + " for " + locationKey);
    }
    
    /**
     * 缓存预报数据
     */
    public void cacheForecast(String locationKey, WeatherData[] forecast, String sourceId, long latency) {
        String cacheKey = generateCacheKey(locationKey, sourceId);
        CachedWeatherData[] cachedForecast = new CachedWeatherData[forecast.length];
        
        for (int i = 0; i < forecast.length; i++) {
            cachedForecast[i] = new CachedWeatherData(forecast[i], sourceId, latency);
        }
        
        forecastCache.put(cacheKey, cachedForecast);
        
        // 更新可靠性统计
        reliabilityStats.computeIfAbsent(sourceId, k -> new SourceReliabilityStats())
                       .recordSuccess(latency);
        
        System.out.println("Cached forecast from " + sourceId + " for " + locationKey);
    }
    
    /**
     * 获取缓存的当前天气数据
     */
    public CachedWeatherData getCachedCurrentWeather(String locationKey, String sourceId) {
        String cacheKey = generateCacheKey(locationKey, sourceId);
        CachedWeatherData cached = currentWeatherCache.get(cacheKey);
        
        if (cached != null && !cached.isExpired(DEFAULT_CACHE_MINUTES)) {
            return cached;
        }
        
        // 清理过期缓存
        if (cached != null) {
            currentWeatherCache.remove(cacheKey);
        }
        
        return null;
    }
    
    /**
     * 获取缓存的预报数据
     */
    public CachedWeatherData[] getCachedForecast(String locationKey, String sourceId) {
        String cacheKey = generateCacheKey(locationKey, sourceId);
        CachedWeatherData[] cached = forecastCache.get(cacheKey);
        
        if (cached != null && cached.length > 0 && !cached[0].isExpired(DEFAULT_CACHE_MINUTES)) {
            return cached;
        }
        
        // 清理过期缓存
        if (cached != null) {
            forecastCache.remove(cacheKey);
        }
        
        return null;
    }
    
    /**
     * 记录API源失败
     */
    public void recordSourceFailure(String sourceId) {
        reliabilityStats.computeIfAbsent(sourceId, k -> new SourceReliabilityStats())
                       .recordFailure();
        System.out.println("Recorded failure for source: " + sourceId);
    }
    
    /**
     * 聚合多源天气数据，返回最可靠的结果
     */
    public WeatherData aggregateCurrentWeatherData(List<CachedWeatherData> dataList) {
        if (dataList.isEmpty()) {
            return null;
        }
        
        if (dataList.size() == 1) {
            return dataList.get(0).getData();
        }
        
        // 按源可靠性排序
        dataList.sort((a, b) -> {
            double scoreA = getSourceReliabilityScore(a.getSourceId());
            double scoreB = getSourceReliabilityScore(b.getSourceId());
            return Double.compare(scoreB, scoreA); // 降序排列
        });
        
        // 数据验证和聚合
        List<WeatherData> validData = new ArrayList<>();
        for (CachedWeatherData cached : dataList) {
            if (isDataValid(cached.getData())) {
                validData.add(cached.getData());
            }
        }
        
        if (validData.isEmpty()) {
            // 如果没有有效数据，返回最高可靠性源的数据
            return dataList.get(0).getData();
        }
        
        // 检查数据一致性
        if (areDataConsistent(validData)) {
            // 数据一致，返回最可靠源的数据
            return validData.get(0);
        } else {
            // 数据不一致，使用加权平均
            return calculateWeightedAverage(dataList);
        }
    }
    
    /**
     * 计算加权平均天气数据
     */
    private WeatherData calculateWeightedAverage(List<CachedWeatherData> dataList) {
        double totalWeight = 0.0;
        double weightedTemp = 0.0;
        double weightedHumidity = 0.0;
        double weightedWindSpeed = 0.0;
        String primaryDescription = "";
        String primaryDate = "";
        UserPreferences userPrefs = null;
        
        for (CachedWeatherData cached : dataList) {
            double weight = getSourceReliabilityScore(cached.getSourceId());
            
            if (weight > 0 && isDataValid(cached.getData())) {
                WeatherData data = cached.getData();
                weightedTemp += data.getTemperature() * weight;
                weightedHumidity += data.getHumidity() * weight;
                weightedWindSpeed += data.getWindSpeed() * weight;
                totalWeight += weight;
                
                // 使用最可靠源的描述和日期
                if (primaryDescription.isEmpty()) {
                    primaryDescription = data.getDescription();
                    primaryDate = data.getForecastDate();
                    userPrefs = data.getUserPreferences();
                }
            }
        }
        
        if (totalWeight > 0) {
            return new WeatherData(
                weightedTemp / totalWeight,
                weightedHumidity / totalWeight,
                weightedWindSpeed / totalWeight,
                primaryDescription + " (Aggregated)",
                primaryDate,
                userPrefs
            );
        }
        
        // 回退到第一个有效数据
        return dataList.get(0).getData();
    }
    
    /**
     * 检查数据是否有效
     */
    private boolean isDataValid(WeatherData data) {
        return data != null &&
               data.getTemperature() >= -50 && data.getTemperature() <= 60 && // 合理温度范围
               data.getHumidity() >= 0 && data.getHumidity() <= 100 && // 湿度百分比
               data.getWindSpeed() >= 0 && data.getWindSpeed() <= 150; // 合理风速范围
    }
    
    /**
     * 检查多个数据源的数据是否一致
     */
    private boolean areDataConsistent(List<WeatherData> dataList) {
        if (dataList.size() <= 1) return true;
        
        WeatherData reference = dataList.get(0);
        
        for (int i = 1; i < dataList.size(); i++) {
            WeatherData compare = dataList.get(i);
            
            if (Math.abs(reference.getTemperature() - compare.getTemperature()) > TEMPERATURE_VARIANCE_THRESHOLD ||
                Math.abs(reference.getHumidity() - compare.getHumidity()) > HUMIDITY_VARIANCE_THRESHOLD) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 获取源可靠性分数
     */
    public double getSourceReliabilityScore(String sourceId) {
        SourceReliabilityStats stats = reliabilityStats.get(sourceId);
        return stats != null ? stats.getReliabilityScore() : 0.5; // 默认中等可靠性
    }
    
    /**
     * 获取源可靠性统计
     */
    public SourceReliabilityStats getSourceStats(String sourceId) {
        return reliabilityStats.get(sourceId);
    }
    
    /**
     * 获取所有源的统计信息
     */
    public Map<String, SourceReliabilityStats> getAllSourceStats() {
        return new ConcurrentHashMap<>(reliabilityStats);
    }
    
    /**
     * 清理过期缓存
     */
    public void cleanupExpiredCache() {
        // 清理当前天气缓存
        currentWeatherCache.entrySet().removeIf(entry -> 
            entry.getValue().isExpired(DEFAULT_CACHE_MINUTES));
        
        // 清理预报缓存
        forecastCache.entrySet().removeIf(entry -> {
            CachedWeatherData[] forecast = entry.getValue();
            return forecast.length == 0 || forecast[0].isExpired(DEFAULT_CACHE_MINUTES);
        });
        
        System.out.println("Cleaned up expired cache entries");
    }
    
    /**
     * 生成缓存键
     */
    private String generateCacheKey(String locationKey, String sourceId) {
        return locationKey + "_" + sourceId;
    }
    
    /**
     * 获取缓存统计信息
     */
    public String getCacheStats() {
        return String.format("Current weather cache: %d entries, Forecast cache: %d entries, " +
                           "Reliability stats: %d sources",
                           currentWeatherCache.size(),
                           forecastCache.size(),
                           reliabilityStats.size());
    }
} 